﻿#region Using

using System;
using System.Linq;
using System.Security.Authentication;
using System.Text.RegularExpressions;
using System.Windows.Navigation;

#endregion

namespace Vk.Authorization
{
    /// <summary>
    ///     Логика страницы авторизации
    /// </summary>
    public partial class WpfAuthPage : IAuthClient
    {
        /// <summary>
        ///     Ссылка на страницу авторизации
        /// </summary>
        protected string AuthPath
        {
            get
            {
                return "https://oauth.vk.com/authorize?" +
                       "client_id=" + AppId + "&" +
                       "redirect_uri=https://oauth.vk.com/blank.html&" +
                       (Permissions != null && Permissions.Values.Any() ? "scope=" + Permissions + "&" : string.Empty) +
                       "response_type=token&" +
                       "display=popup";
            }
        }

        public WpfAuthPage(int appId, ApiAccessPermissions permissions = null)
        {
            AppId = appId;
            Permissions = permissions;
            InitializeComponent();
            WebView.LoadCompleted += webView_LoadCompleted;
            WebView.Navigate(AuthPath);
        }

        /// <summary>
        ///     Идентификатор приложения Вконтакте
        /// </summary>
        public int AppId { get; }

        /// <summary>
        ///     Разрешения, которые запрашиваются во время авторизации
        /// </summary>
        public ApiAccessPermissions Permissions { get; }

        /// <summary>
        ///     Событие успешного завершения авторизации
        /// </summary>
        public event EventHandler<AuthSuccessEventArgs> AuthSuccess;

        /// <summary>
        ///     Событие возникает при ошибке авторизации
        /// </summary>
        public event EventHandler<AuthFailEventArgs> AuthFail;

        /// <summary>
        ///     Пытается получить токен из URL
        /// </summary>
        /// <param name="respUri">URL</param>
        /// <param name="session">Обьект сессии, который нужно заполнить</param>
        /// <returns>true - если удалось</returns>
        private bool TryGetToken(Uri respUri, ref VkSession session)
        {
            //Поиск ошибки
            var isError = new Regex("error").IsMatch(respUri.Fragment);
            if (isError)
            {
                var parts = respUri.Fragment.Split('&');
                var type = parts[0].Replace("error=", "");
                var desc = parts[1].Replace("error_description=", "");
                throw new AuthenticationException(string.Format("{}: {}", type, desc));
            }

            //Инициализация регулярных выражений
            var accessTokenRegex = new Regex("access_token");
            var userIdRegex = new Regex("user_id");
            var expiresInRegex = new Regex("expires_in");

            //Разбиение url на куски
            var chunks = respUri.Fragment.Split(new[] {"&"}, StringSplitOptions.None);

            var authDone = false; //Флаг успешной авторизации
            //Проход по всем кускам и поиск нужной информации
            foreach (var chunk in chunks)
            {
                if (accessTokenRegex.IsMatch(chunk))
                {
                    session.AccessToken = chunk.Replace("access_token=", "")
                                               .Replace("#", "")
                                               .Replace("&", "");
                    authDone = true;
                }
                if (userIdRegex.IsMatch(chunk))
                    session.UserId =
                        int.Parse(chunk.Replace("user_id=", "").Replace("#", "").Replace("&", ""));
                if (expiresInRegex.IsMatch(chunk))
                    session.Expires =
                        DateTime.Now + TimeSpan.FromSeconds(double.Parse(chunk.Replace("expires_in=", "")
                                                                              .Replace("#", "")
                                                                              .Replace("&", "")));
            }
            return authDone;
        }

        private void webView_LoadCompleted(object sender, NavigationEventArgs e)
        {
            var uri = e.Uri;
            if (uri.Host != "oauth.vk.com") //Хост страницы с результатом авторизации - oauth.vk.com
                return;

            var session = new VkSession(AppId);
            try
            {
                var success = TryGetToken(uri, ref session);
                if (success && AuthSuccess != null)
                {
                    AuthSuccess(this, new AuthSuccessEventArgs(session));
                }
            }
            catch (AuthenticationException exc)
            {
                if (AuthFail != null)
                    AuthFail(this, new AuthFailEventArgs(AuthFailEventArgs.FailType.APIError, exc.Message));
            }
            catch (Exception exc)
            {
                if (AuthFail != null)
                    AuthFail(this, new AuthFailEventArgs(AuthFailEventArgs.FailType.LocalException, exc.Message));
            }
        }
    }
}